from django.db import models
from django.core.validators import RegexValidator
from django.contrib.auth.models import User
import os
from PIL import Image
from io import BytesIO
from django.core.files.base import ContentFile
import qrcode

class Bicycle(models.Model):
    """自行车模型"""
    
    # 自行车类别选择
    CATEGORY_CHOICES = [
        ('mountain', '山地车'),
        ('road', '公路车'),
        ('city', '城市车'),
        ('electric', '电动车'),
        ('folding', '折叠车'),
        ('bmx', 'BMX'),
        ('other', '其他'),
    ]
    
    # 学院选择
    COLLEGE_CHOICES = [
        ('computer', '计算机与人工智能学院'),
        ('engineering', '能源动力与工程学院'),
        ('business', '数字经济与管理学院'),
        ('arts', '艺术学院'),
        ('media', '传媒学院'),
        ('education', '教育学院'),
        ('humanities', '人文学院'),
        ('marx', '马克思主义学院'),
        ('continue', '继续教育学院'),
        ('international', '国际教育学院'),
        ('office', '学校办公室'),
        ('party', '党委办公室'),
        ('student', '学生工作处'),
        ('security', '后勤保卫处'),
        ('teaching', '教务处'),
        ('finance', '财务处'),
        ('construction', '基建处'),
        ('information', '图文信息中心'),
        ('recruit', '招生办'),
        ('bidding', '招标采购办公室'),
        ('other', '其他'),
    ]
    
    # 学院简称映射
    COLLEGE_SHORT_NAMES = {
        'computer': 'CS',      # 计算机与人工智能学院
        'engineering': 'EN',   # 能源动力与工程学院
        'business': 'BU',      # 数字经济与管理学院
        'arts': 'AR',          # 艺术学院
        'media': 'ME',         # 传媒学院
        'education': 'ED',     # 教育学院
        'humanities': 'HU',    # 人文学院
        'marx': 'MA',          # 马克思主义学院
        'continue': 'CO',      # 继续教育学院
        'international': 'IN', # 国际教育学院
        'office': 'OF',        # 学校办公室
        'party': 'PA',         # 党委办公室
        'student': 'ST',       # 学生工作处
        'security': 'SE',      # 后勤保卫处
        'teaching': 'TE',      # 教务处
        'finance': 'FI',       # 财务处
        'construction': 'CN',  # 基建处
        'information': 'IF',   # 图文信息中心
        'recruit': 'RE',       # 招生办
        'bidding': 'BI',       # 招标采购办公室
        'other': 'OT',         # 其他
    }
    
    # 自行车编号 - 唯一标识
    bike_number = models.CharField(
        max_length=20,
        unique=True,
        verbose_name='自行车编号',
        blank=True,
        null=True,
        validators=[RegexValidator(
            regex=r'^[A-Z0-9]+$',
            message='自行车编号只能包含大写字母和数字'
        )],
        help_text='自动生成：学院简称+序号，如CS001, EN001等'
    )
    
    # 型号
    model = models.CharField(
        max_length=100,
        verbose_name='型号',
        help_text='自行车的具体型号'
    )
    
    # 所有人姓名
    owner_name = models.CharField(
        max_length=50,
        verbose_name='所有人',
        help_text='自行车所有者的姓名'
    )
    
    # 所有人学号
    owner_student_id = models.CharField(
        max_length=20,
        verbose_name='学号',
        help_text='所有人的学号',
        blank=True,
        null=True
    )
    
    # 类别
    category = models.CharField(
        max_length=20,
        choices=CATEGORY_CHOICES,
        verbose_name='类别',
        help_text='自行车的类型'
    )
    
    # 学院
    college = models.CharField(
        max_length=20,
        choices=COLLEGE_CHOICES,
        verbose_name='学院',
        help_text='所有人所属学院'
    )
    
    # 班级
    class_name = models.CharField(
        max_length=50,
        verbose_name='班级',
        help_text='所有人所属班级',
        blank=True,
        null=True
    )
    
    # 联系电话
    phone_number = models.CharField(
        max_length=20,
        verbose_name='联系电话',
        help_text='所有人的联系电话',
        blank=True,
        null=True,
        validators=[RegexValidator(
            regex=r'^1[3-9]\d{9}$',
            message='请输入有效的手机号码'
        )]
    )
    
    # 购买日期
    purchase_date = models.DateField(
        verbose_name='购买日期',
        help_text='自行车的购买日期',
        blank=True,
        null=True
    )
    
    # 颜色
    color = models.CharField(
        max_length=20,
        verbose_name='颜色',
        help_text='自行车的主要颜色',
        blank=True,
        null=True
    )
    
    # 自行车图片
    image = models.ImageField(
        upload_to='bike_images/',
        verbose_name='自行车图片',
        help_text='上传自行车照片',
        blank=True,
        null=True
    )
    
    # 二维码图片
    qr_code = models.ImageField(
        upload_to='qr_codes/',
        verbose_name='二维码',
        help_text='自动生成的二维码',
        blank=True,
        null=True
    )
    
    # 备注
    notes = models.TextField(
        verbose_name='备注',
        help_text='其他相关信息',
        blank=True,
        null=True
    )
    
    # 创建时间
    created_at = models.DateTimeField(
        auto_now_add=True,
        verbose_name='创建时间'
    )
    
    # 更新时间
    updated_at = models.DateTimeField(
        auto_now=True,
        verbose_name='更新时间'
    )
    
    class Meta:
        verbose_name = '自行车'
        verbose_name_plural = '自行车管理'
        ordering = ['-created_at']
    
    def __str__(self):
        return f"{self.bike_number} - {self.owner_name} ({self.get_category_display()})"
    
    def get_owner_info(self):
        """获取所有人完整信息"""
        info = f"{self.owner_name}"
        if self.owner_student_id:
            info += f" ({self.owner_student_id})"
        if self.class_name:
            info += f" - {self.class_name}"
        return info
    
    def generate_bike_number(self):
        """自动生成自行车编号"""
        if not self.college:
            return None
        
        # 获取学院简称
        college_short = self.COLLEGE_SHORT_NAMES.get(self.college, 'OT')
        
        # 查找该学院已有的最大编号
        existing_numbers = Bicycle.objects.filter(
            bike_number__startswith=college_short
        ).values_list('bike_number', flat=True)
        
        # 提取数字部分并找到最大值
        max_num = 0
        for number in existing_numbers:
            if number and number.startswith(college_short):
                try:
                    # 提取数字部分
                    num_part = number[len(college_short):]
                    if num_part.isdigit():
                        max_num = max(max_num, int(num_part))
                except (ValueError, IndexError):
                    continue
        
        # 生成新编号（4位数字，不足补0）
        new_num = max_num + 1
        return f"{college_short}{new_num:04d}"
    
    def generate_qr_code(self):
        """生成二维码"""
        if not self.bike_number:
            return None
        
        # 创建二维码内容（包含自行车详情页面的URL）
        # 可以从Django设置中获取域名，或者直接修改为您的域名
        from django.conf import settings
        domain = getattr(settings, 'QR_CODE_DOMAIN', 'http://127.0.0.1:8000')
        qr_content = f"{domain}/bike/{self.bike_number}/"
        
        # 生成二维码
        qr = qrcode.QRCode(
            version=1,
            error_correction=qrcode.constants.ERROR_CORRECT_L,
            box_size=10,
            border=4,
        )
        qr.add_data(qr_content)
        qr.make(fit=True)
        
        # 创建二维码图片
        qr_image = qr.make_image(fill_color="black", back_color="white")
        
        # 在二维码下方添加自行车编号
        from PIL import Image, ImageDraw, ImageFont
        import os
        
        # 确保二维码图片是RGB模式
        if qr_image.mode != 'RGB':
            qr_image = qr_image.convert('RGB')
        
        # 获取二维码尺寸
        qr_width, qr_height = qr_image.size
        
        # 创建新图片，为文字留出空间
        text_height = 30  # 文字区域高度（减少）
        new_height = qr_height + text_height
        
        # 创建新图片
        new_image = Image.new('RGB', (qr_width, new_height), 'white')
        
        # 粘贴二维码到新图片
        new_image.paste(qr_image, (0, 0))
        
        # 添加自行车编号文字
        draw = ImageDraw.Draw(new_image)
        
        # 尝试使用支持中文的系统字体
        font = None
        font_paths = [
            # Windows中文字体
            "C:/Windows/Fonts/simhei.ttf",  # 黑体
            "C:/Windows/Fonts/simsun.ttc",  # 宋体
            "C:/Windows/Fonts/msyh.ttc",    # 微软雅黑
            "C:/Windows/Fonts/arial.ttf",   # Arial
            # Linux中文字体
            "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc",
            "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
            # macOS中文字体
            "/System/Library/Fonts/PingFang.ttc",
            "/System/Library/Fonts/Helvetica.ttc",
        ]
        
        for font_path in font_paths:
            try:
                if os.path.exists(font_path):
                    font = ImageFont.truetype(font_path, 18)  # 稍微减小字体
                    break
            except:
                continue
        
        # 如果所有字体都失败，使用默认字体
        if font is None:
            font = ImageFont.load_default()
        
        # 计算文字位置（居中）
        text = f"编号: {self.bike_number}"
        bbox = draw.textbbox((0, 0), text, font=font)
        text_width = bbox[2] - bbox[0]
        text_x = (qr_width - text_width) // 2
        text_y = qr_height + 3  # 减少距离，从10改为5
        
        # 绘制文字
        draw.text((text_x, text_y), text, fill='black', font=font)
        
        # 转换为Django文件
        buffer = BytesIO()
        new_image.save(buffer, format='PNG')
        buffer.seek(0)
        
        # 保存到模型字段
        filename = f"qr_{self.bike_number}.png"
        self.qr_code.save(filename, ContentFile(buffer.getvalue()), save=False)
        
        return self.qr_code
    
    def compress_image(self, image_field, max_size_kb=200):
        """压缩图片到指定大小（KB）"""
        if not image_field:
            return None
            
        # 打开图片
        image = Image.open(image_field)
        
        # 转换为RGB模式（如果是RGBA）
        if image.mode in ('RGBA', 'LA', 'P'):
            image = image.convert('RGB')
        
        # 计算目标质量
        quality = 95
        max_size_bytes = max_size_kb * 1024
        
        # 创建字节流
        output = BytesIO()
        
        # 尝试不同的质量设置直到文件大小符合要求
        while quality > 10:
            output.seek(0)
            output.truncate()
            
            # 保存图片
            image.save(output, format='JPEG', quality=quality, optimize=True)
            
            # 检查文件大小
            if output.tell() <= max_size_bytes:
                break
                
            # 如果文件太大，降低质量
            quality -= 10
        
        # 如果质量降到10还是太大，尝试缩小图片尺寸
        if output.tell() > max_size_bytes:
            # 计算缩放比例
            scale_factor = (max_size_bytes / output.tell()) ** 0.5
            new_width = int(image.width * scale_factor)
            new_height = int(image.height * scale_factor)
            
            # 确保最小尺寸
            new_width = max(new_width, 100)
            new_height = max(new_height, 100)
            
            # 重新调整图片大小
            image = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
            
            # 重新保存
            output.seek(0)
            output.truncate()
            image.save(output, format='JPEG', quality=85, optimize=True)
        
        # 创建新的ContentFile
        output.seek(0)
        return ContentFile(output.getvalue())
    
    def save(self, *args, **kwargs):
        """保存时自动生成编号和二维码"""
        # 如果有上传的图片，先压缩
        if self.image and hasattr(self.image, 'file'):
            compressed_image = self.compress_image(self.image)
            if compressed_image:
                # 生成新的文件名
                original_name = self.image.name
                name, ext = os.path.splitext(original_name)
                new_name = f"{name}_compressed.jpg"
                
                # 保存压缩后的图片
                self.image.save(new_name, compressed_image, save=False)
        
        if not self.bike_number and self.college:
            self.bike_number = self.generate_bike_number()
        
        super().save(*args, **kwargs)
        
        # 生成二维码
        if not self.qr_code:
            self.generate_qr_code()
            super().save(*args, **kwargs)


class ViolationRecord(models.Model):
    """违章记录模型"""
    
    # 违章类型选择
    VIOLATION_TYPES = [
        ('parking', '乱停乱放'),
        ('mismatch', '证物不符'),
        ('theft', '疑似盗窃'),
        ('abandon', '长期闲置'),
        ('other', '其他'),
    ]
    
    # 违章状态选择
    STATUS_CHOICES = [
        ('pending', '待处理'),
        ('processing', '处理中'),
        ('resolved', '已解决'),
        ('dismissed', '已撤销'),
    ]
    
    bicycle = models.ForeignKey(
        Bicycle,
        on_delete=models.CASCADE,
        verbose_name='自行车',
        related_name='violations'
    )
    
    violation_type = models.CharField(
        max_length=20,
        choices=VIOLATION_TYPES,
        verbose_name='违章类型'
    )
    
    description = models.TextField(
        verbose_name='违章描述',
        help_text='详细描述违章情况'
    )
    
    location = models.CharField(
        max_length=200,
        verbose_name='违章地点',
        help_text='违章发生的具体地点'
    )
    
    reporter_name = models.CharField(
        max_length=50,
        verbose_name='检查人姓名',
        blank=True,
        null=True
    )
    
    reporter_phone = models.CharField(
        max_length=20,
        verbose_name='检查人电话',
        blank=True,
        null=True
    )
    
    status = models.CharField(
        max_length=20,
        choices=STATUS_CHOICES,
        default='pending',
        verbose_name='处理状态'
    )
    
    violation_images = models.ImageField(
        upload_to='violation_images/',
        verbose_name='违章照片',
        blank=True,
        null=True
    )
    
    created_at = models.DateTimeField(
        auto_now_add=True,
        verbose_name='举报时间'
    )
    
    updated_at = models.DateTimeField(
        auto_now=True,
        verbose_name='更新时间'
    )
    
    class Meta:
        verbose_name = '违章记录'
        verbose_name_plural = '违章记录管理'
        ordering = ['-created_at']
    
    def compress_image(self, image_field, max_size_kb=200):
        """压缩图片到指定大小（KB）"""
        if not image_field:
            return None
            
        # 打开图片
        image = Image.open(image_field)
        
        # 转换为RGB模式（如果是RGBA）
        if image.mode in ('RGBA', 'LA', 'P'):
            image = image.convert('RGB')
        
        # 计算目标质量
        quality = 95
        max_size_bytes = max_size_kb * 1024
        
        # 创建字节流
        output = BytesIO()
        
        # 尝试不同的质量设置直到文件大小符合要求
        while quality > 10:
            output.seek(0)
            output.truncate()
            
            # 保存图片
            image.save(output, format='JPEG', quality=quality, optimize=True)
            
            # 检查文件大小
            if output.tell() <= max_size_bytes:
                break
                
            # 如果文件太大，降低质量
            quality -= 10
        
        # 如果质量降到10还是太大，尝试缩小图片尺寸
        if output.tell() > max_size_bytes:
            # 计算缩放比例
            scale_factor = (max_size_bytes / output.tell()) ** 0.5
            new_width = int(image.width * scale_factor)
            new_height = int(image.height * scale_factor)
            
            # 确保最小尺寸
            new_width = max(new_width, 100)
            new_height = max(new_height, 100)
            
            # 重新调整图片大小
            image = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
            
            # 重新保存
            output.seek(0)
            output.truncate()
            image.save(output, format='JPEG', quality=85, optimize=True)
        
        # 创建新的ContentFile
        output.seek(0)
        return ContentFile(output.getvalue())
    
    def save(self, *args, **kwargs):
        """保存时自动压缩图片"""
        # 如果有上传的图片，先压缩
        if self.violation_images and hasattr(self.violation_images, 'file'):
            compressed_image = self.compress_image(self.violation_images)
            if compressed_image:
                # 生成新的文件名
                original_name = self.violation_images.name
                name, ext = os.path.splitext(original_name)
                new_name = f"{name}_compressed.jpg"
                
                # 保存压缩后的图片
                self.violation_images.save(new_name, compressed_image, save=False)
        
        super().save(*args, **kwargs)
    
    def __str__(self):
        return f"{self.bicycle.bike_number} - {self.get_violation_type_display()}"


class CollegeUser(models.Model):
    """学院用户模型"""
    
    user = models.OneToOneField(
        User,
        on_delete=models.CASCADE,
        verbose_name='用户账号'
    )
    
    college = models.CharField(
        max_length=20,
        choices=Bicycle.COLLEGE_CHOICES,
        verbose_name='所属学院'
    )
    
    is_admin = models.BooleanField(
        default=False,
        verbose_name='是否管理员',
        help_text='管理员可以管理本学院所有自行车'
    )
    
    is_super_admin = models.BooleanField(
        default=False,
        verbose_name='是否超级管理员',
        help_text='超级管理员可以管理所有学院和用户'
    )
    
    created_at = models.DateTimeField(
        auto_now_add=True,
        verbose_name='创建时间'
    )
    
    class Meta:
        verbose_name = '学院用户'
        verbose_name_plural = '学院用户管理'
    
    def __str__(self):
        return f"{self.user.username} - {self.get_college_display()}"


class ViolationSecretKey(models.Model):
    """违章提交管理秘钥"""
    secret_key = models.CharField(
        max_length=4,
        unique=True,
        validators=[RegexValidator(r'^\d{4}$', '秘钥必须是4位数字')],
        verbose_name='管理秘钥',
        help_text='4位数字秘钥，用于验证违章信息提交权限'
    )
    is_active = models.BooleanField(
        default=True,
        verbose_name='是否启用',
        help_text='启用后，提交违章信息时需要输入此秘钥'
    )
    created_at = models.DateTimeField(
        auto_now_add=True,
        verbose_name='创建时间'
    )
    updated_at = models.DateTimeField(
        auto_now=True,
        verbose_name='更新时间'
    )
    created_by = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        verbose_name='创建者'
    )
    
    class Meta:
        verbose_name = '违章提交秘钥'
        verbose_name_plural = '违章提交秘钥管理'
        ordering = ['-created_at']
    
    def __str__(self):
        return f"秘钥: {self.secret_key} ({'启用' if self.is_active else '禁用'})"
    
    @classmethod
    def get_active_key(cls):
        """获取当前激活的秘钥"""
        try:
            return cls.objects.filter(is_active=True).first()
        except cls.DoesNotExist:
            return None
    
    @classmethod
    def validate_key(cls, key):
        """验证秘钥是否正确"""
        active_key = cls.get_active_key()
        if not active_key:
            return False, "未设置管理秘钥"
        if active_key.secret_key != key:
            return False, "秘钥错误"
        return True, "验证成功"
